package com.xyx.uniplugin_bloodoxygen;


import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.xyx.uniplugin_bloodoxygen.datastructs.Result;
import com.xyx.uniplugin_bloodoxygen.device.BloodDevice;
import com.xyx.uniplugin_bloodoxygen.device.NormalDevice;
import com.xyx.uniplugin_bloodoxygen.filters.OxygenParamFilter;
import com.xyx.uniplugin_bloodoxygen.filters.WaveFormFilter;
import com.xyx.xyxandwxx_ble.async.AsyncExecute;
import com.xyx.xyxandwxx_ble.async.IAsyncTask;
import com.xyx.xyxandwxx_ble.devices.DeviceMonitor;
import com.xyx.xyxandwxx_ble.utils.PermissionUtils;

import java.util.UUID;

import io.dcloud.common.core.permission.PermissionControler;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

/**
 * 血氧模块
 */
public class BloodOxygenModule extends UniModule {

    private static final String TAG = "BloodOxygenModule";
    /**
     * 设备管理
     */
    private DeviceMonitor deviceMonitor;
    /**
     * 设备
     */
    private BloodDevice device;
    /**
     * 呼吸设备
     */
    private NormalDevice fxDevice;


    final int REQUEST_CODE = 11111;
    /**
     * 权限列表
     */
    public static String[] lowPermissions = new String[]{
            "android.permission.BLUETOOTH_ADMIN", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"
    };

    /**
     * 高权限列表
     */
    public static String[] highPermissions = new String[]{
            "android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_CONNECT"
    };

    /**
     * 获取结果
     * @param success 是否成功
     * @return 结果字符串
     */
    public String getResult(boolean success) {
        return JSON.toJSONString(success ? Result.success(null) : Result.fail(1, ""));
    }

    /**
     * 成功
     * @param data 数据
     * @return
     */
    public String success(Object data) {
        return JSON.toJSONString(Result.success(data));
    }

    /**
     * 失败
     * @param message
     * @return
     */
    public String fail(String message) {
        return JSON.toJSONString(Result.fail(1, message));
    }

    /**
     * 创建
     * @return 创建是否成功
     */
    @UniJSMethod(uiThread = true)
    public String create() {
        if(deviceMonitor != null)return getResult(true);
        try{
            deviceMonitor = new DeviceMonitor(this.mUniSDKInstance.getContext());
        }catch (Exception e){
            return getResult(false);
        }
        return getResult(true);
    }

    /**
     * 申请权限
     * @return 是否申请成功
     */
    @UniJSMethod(uiThread = true)
    public void requestPermission() {
        Activity activity = (Activity) mUniSDKInstance.getContext();

        PermissionControler.requestPermissions(activity, lowPermissions, 1);
        if(Build.VERSION.SDK_INT >= 31){
            PermissionControler.requestPermissions(activity, highPermissions, 1);
        }
    }


    /**
     * 查询设备 名称
     * @param deviceName 设备名称
     * @param waveCallback 波形数据回调函数
     * @param oxygenParamCallback 血氧参数数据回调函数
     * @return 是否查询成功
     * @exception Exception 查询失败
     */
    @UniJSMethod(uiThread = true)
    public void searchDevice(String deviceName, UniJSCallback waveCallback, UniJSCallback oxygenParamCallback, UniJSCallback findDevice) throws Exception {
        if(deviceMonitor == null) return;
        if(!deviceMonitor.isEnableBlueBooth())return;
        int timeout = 60000;
        deviceMonitor.setOnDeviceFindEvent(event ->{
            if(event.getName() != null && event.getName().equals(deviceName)){
                Log.i(TAG, "搜索到设备 : " + event.getName());
                this.device = new BloodDevice(event);
                this.device.addFilter(new OxygenParamFilter(oxygenParamCallback::invokeAndKeepAlive));
                this.device.addFilter(new WaveFormFilter(waveCallback::invokeAndKeepAlive));
                this.deviceMonitor.stopSearchDeviceServer();

                findDevice.invoke(this.device.device.getName());
            }
        });
        deviceMonitor.startSearchDeviceServer(timeout);
    }


    /**
     * 查询呼吸设备 名称
     * @param deviceName 设备名称
     * @param waveCallback 波形数据回调函数
     * @return 是否查询成功
     * @exception Exception 查询失败
     */
    @UniJSMethod(uiThread = true)
    public void searchFXDevice(String deviceName, UniJSCallback waveCallback, UniJSCallback findDevice) throws Exception {
        if(deviceMonitor == null) return;
        if(!deviceMonitor.isEnableBlueBooth())return;
        int timeout = 60000;
        deviceMonitor.setOnDeviceFindEvent(event ->{
            if(event.getName() != null && event.getName().equals(deviceName)){
                Log.i(TAG, "搜索到设备 : " + event.getName());
                this.fxDevice = new NormalDevice(event);
                this.fxDevice.setCallBack(waveCallback::invokeAndKeepAlive);
                this.deviceMonitor.stopSearchDeviceServer();
                findDevice.invoke(this.fxDevice.device.getName());
            }
        });
        deviceMonitor.startSearchDeviceServer(timeout);
    }

    @UniJSMethod(uiThread = true)
    public void testMethod(UniJSCallback callback) {
        callback.invoke(getResult(true));
    }

    /**
     *  连接设备
     * @param serverId 服务
     * @param writeId 写服务
     * @param readId 读取服务
     * @return 是否连接成功
     */
    @UniJSMethod(uiThread = true)
    public void connectDevice(String serverId, String writeId, String readId, UniJSCallback resCallback){
        if(this.device == null){
            resCallback.invoke(fail("设备未找到"));
            return;
        }
        try {
            device.connect(serverId.toLowerCase(), writeId.toLowerCase(), readId.toLowerCase(), res ->{
                if(res == null || !res){
                    fail("连接失败");
                }else{
                    resCallback.invoke(success(null));
                }
            });
        } catch (Exception e) {
            resCallback.invoke(fail(e.getMessage()));
        }
    }

    /**
     *  连接设备
     * @param serverId 服务
     * @param writeId 写服务
     * @param readId 读取服务
     * @return 是否连接成功
     */
    @UniJSMethod(uiThread = true)
    public void connectFxDevice(String serverId, String writeId, String readId, UniJSCallback resCallback){
        if(this.fxDevice == null){
            resCallback.invoke(fail("设备未找到"));
            return;
        }
        try {
            fxDevice.connect(serverId.toLowerCase(), writeId.toLowerCase(), readId.toLowerCase(), res ->{
                if(res == null || !res){
                    fail("连接失败");
                }else{
                    resCallback.invoke(success(null));
                }
            });
        } catch (Exception e) {
            resCallback.invoke(fail(e.getMessage()));
        }
    }

    /**
     * 是否完全开启蓝牙
     * @return 是否成功开启蓝牙
     */
    @UniJSMethod(uiThread = true)
    public void isEnableBlueBooth(UniJSCallback callback) {
        if(deviceMonitor == null) {
            callback.invoke(success(null));
        }else{
            callback.invoke(getResult(deviceMonitor.isEnableBlueBooth()));
        }
    }

    /**
     * 打开发送波形数据回调
     * @return 是否打开成功
     * @exception Exception 打开异常
     */
    @UniJSMethod(uiThread = true)
    public void openWaveFormCallback(UniJSCallback callback) {
        if(deviceMonitor == null || device == null || !device.isConnected()) {
            callback.invoke(fail("设备未连接!"));
            return;
        }
        try {
            device.openWaveFormData(res ->{
                callback.invoke(getResult(res != null && res));
            });
        } catch (Exception e) {
            callback.invoke(fail(e.getMessage()));
        }
    }

    /**
     * 关闭波形数据回调
     * @return 是否关闭成功
     * @throws Exception 关闭异常
     */
    @UniJSMethod(uiThread = true)
    public void closeWaveFormCallback(UniJSCallback callback) throws Exception {
        if(deviceMonitor == null || device == null || !device.isConnected()){
            callback.invoke(success(null));
            return;
        }
        device.closeWaveFormData(res ->{
            callback.invoke(getResult(res != null && res));
        });
    }

    /**
     * 打开血氧数据回调
     * @return 是否打开成功
     * @exception Exception 打开异常
     */
    @UniJSMethod(uiThread = true)
    public void openListenBloodOxygenParam(UniJSCallback callback) throws Exception {
        if(deviceMonitor == null || device == null || !device.isConnected()) {
            callback.invoke(fail("设备未连接!"));
            return;
        }
        try {
            device.openListenBloodOxygenParam(res ->{
                callback.invoke(getResult(res != null && res));
            });
        } catch (Exception e) {
            callback.invoke(fail(e.getMessage()));
        }
    }

    /**
     * 关闭血氧数据回调
     * @return 是否关闭成功
     * @throws Exception 关闭异常
     */
    @UniJSMethod(uiThread = true)
    public void closeListenBloodOxygenParam(UniJSCallback callback) throws Exception {
        if(deviceMonitor == null || device == null || !device.isConnected()){
            callback.invoke(success(null));
            return;
        }
        device.closeListenBloodOxygenParam(res ->{
            callback.invoke(getResult(res != null && res));
        });
    }

}
